// 导入所需的 NestJS 装饰器和工具
import {
  Controller,
  Get,
  Post,
  Param,
  UploadedFile,
  UseInterceptors,
  Res,
  HttpStatus,
  HttpException,
  StreamableFile,
  ParseFilePipeBuilder,
  Headers,
  Header,
} from '@nestjs/common';
// 导入文件上传拦截器
import { FileInterceptor } from '@nestjs/platform-express';
// 导入文件服务
import { FileService } from './file.service';
// 导入 Express 的响应类型
import { Response } from 'express';
// 导入文件系统的创建读取流方法
import { createReadStream, statSync } from 'fs';
// 导入路径处理工具
import { join } from 'path';
// 导入配置服务
import { ConfigService } from '@nestjs/config';
import { createGzip } from 'zlib';

// 定义文件控制器，处理 '/files' 路径下的请求
@Controller('files')
export class FileController {
  // 构造函数，注入所需的服务
  constructor(
    private readonly fileService: FileService,
    private readonly configService: ConfigService,
  ) {}

  // 处理文件上传的路由
  @Post('upload')
  // 使用文件拦截器处理上传的文件
  @UseInterceptors(FileInterceptor('file'))
  async uploadFile(
    // 验证上传的文件
    @UploadedFile(
      new ParseFilePipeBuilder()
        // 添加文件大小限制验证
        .addMaxSizeValidator({
          maxSize: parseInt(process.env.FILE_MAX_SIZE),
        })
        // 构建验证管道
        .build({
          fileIsRequired: true,
        }),
    )
    file: Express.Multer.File,
  ) {
    // 检查文件是否存在
    if (!file) {
      throw new HttpException('No file uploaded', HttpStatus.BAD_REQUEST);
    }

    // 保存文件并返回结果
    return this.fileService.saveFile(file);
  }

  // 处理文件下载的路由
  @Get('download/:filename')
  @Header('Accept-Ranges', 'bytes')
  async downloadFile(
    @Param('filename') filename: string,
    @Headers('range') range: string,
    @Headers('accept-encoding') acceptEncoding: string,
    @Res() res: Response,
  ) {
    try {
      const fileInfo = await this.fileService.getFileInfo(filename);
      const filePath = join(process.cwd(), 'uploads', fileInfo.filename);
      const { size } = statSync(filePath);
      const encodedFilename = encodeURIComponent(fileInfo.originalname);

      // 处理 Range 请求（分片下载）
      if (range) {
        const parts = range.replace(/bytes=/, '').split('-');
        const start = parseInt(parts[0], 10);
        const end = parts[1] ? parseInt(parts[1], 10) : size - 1;
        const chunkSize = end - start + 1;

        if (start >= size || end >= size || start > end) {
          res.status(416).send('请求的范围无效');
          return;
        }

        res.set({
          'Content-Type': fileInfo.mimetype,
          'Content-Length': chunkSize,
          'Content-Range': `bytes ${start}-${end}/${size}`,
          'Content-Disposition': `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`,
          'Access-Control-Expose-Headers': 'Content-Disposition',
          'Cache-Control': 'no-cache',
        });
        res.status(206);

        const fileStream = createReadStream(filePath, { start, end });

        // 如果客户端支持压缩且文件大小超过1MB，使用Gzip压缩
        if (acceptEncoding?.includes('gzip') && chunkSize > 1024 * 1024) {
          res.set('Content-Encoding', 'gzip');
          const gzip = createGzip();
          fileStream.pipe(gzip).pipe(res);
        } else {
          fileStream.pipe(res);
        }
      } else {
        // 完整下载
        res.set({
          'Content-Type': fileInfo.mimetype,
          'Content-Length': size,
          'Content-Disposition': `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`,
          'Access-Control-Expose-Headers': 'Content-Disposition',
          'Cache-Control': 'no-cache',
        });

        const fileStream = createReadStream(filePath);

        // 如果客户端支持压缩且文件大小超过1MB，使用Gzip压缩
        if (acceptEncoding?.includes('gzip') && size > 1024 * 1024) {
          res.set('Content-Encoding', 'gzip');
          const gzip = createGzip();
          fileStream.pipe(gzip).pipe(res);
        } else {
          fileStream.pipe(res);
        }
      }
    } catch (error) {
      throw new HttpException('文件未找到', HttpStatus.NOT_FOUND);
    }
  }

  // 处理文件流式传输的路由
  @Get('stream/:filename')
  async streamFile(@Param('filename') filename: string, @Res({ passthrough: true }) res: Response) {
    try {
      // 获取文件信息
      const fileInfo = await this.fileService.getFileInfo(filename);
      // 创建文件读取流
      const file = createReadStream(join(process.cwd(), 'uploads', fileInfo.filename));

      // 对文件名进行 URL 编码
      const encodedFilename = encodeURIComponent(fileInfo.originalname);

      // 设置响应头，inline 表示在浏览器中直接显示
      res.set({
        'Content-Type': fileInfo.mimetype,
        'Content-Disposition': `inline; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`,
        'Access-Control-Expose-Headers': 'Content-Disposition',
      });

      // 返回可流式传输的文件
      return new StreamableFile(file);
    } catch (error) {
      // 文件未找到时抛出异常
      throw new HttpException('File not found', HttpStatus.NOT_FOUND);
    }
  }

  // 获取文件列表的路由
  @Get('list')
  async listFiles() {
    // 返回所有文件的列表
    return this.fileService.listAllFiles();
  }

  // 支持分片下载和断点续传的路由
  @Get('chunk-download/:filename')
  @Header('Accept-Ranges', 'bytes')
  async chunkDownload(
    @Param('filename') filename: string,
    @Headers('range') range: string,
    @Headers('accept-encoding') acceptEncoding: string,
    @Res() res: Response,
  ) {
    try {
      const fileInfo = await this.fileService.getFileInfo(filename);
      const filePath = join(process.cwd(), 'uploads', fileInfo.filename);
      const { size } = statSync(filePath);
      const encodedFilename = encodeURIComponent(fileInfo.originalname);

      // 处理 Range 请求（分片下载）
      if (range) {
        const parts = range.replace(/bytes=/, '').split('-');
        const start = parseInt(parts[0], 10);
        const end = parts[1] ? parseInt(parts[1], 10) : size - 1;
        const chunkSize = end - start + 1;

        res.set({
          'Content-Type': fileInfo.mimetype,
          'Content-Length': chunkSize,
          'Content-Range': `bytes ${start}-${end}/${size}`,
          'Content-Disposition': `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`,
          'Access-Control-Expose-Headers': 'Content-Disposition',
        });
        res.status(206); // Partial Content

        const fileStream = createReadStream(filePath, { start, end });

        // 如果客户端支持压缩且文件大小超过1MB，使用Gzip压缩
        if (acceptEncoding?.includes('gzip') && size > 1024 * 1024) {
          res.set('Content-Encoding', 'gzip');
          const gzip = createGzip();
          fileStream.pipe(gzip).pipe(res);
        } else {
          fileStream.pipe(res);
        }
      } else {
        // 完整下载
        res.set({
          'Content-Type': fileInfo.mimetype,
          'Content-Length': size,
          'Content-Disposition': `attachment; filename="${encodedFilename}"; filename*=UTF-8''${encodedFilename}`,
          'Access-Control-Expose-Headers': 'Content-Disposition',
        });

        const fileStream = createReadStream(filePath);

        // 如果客户端支持压缩且文件大小超过1MB，使用Gzip压缩
        if (acceptEncoding?.includes('gzip') && size > 1024 * 1024) {
          res.set('Content-Encoding', 'gzip');
          const gzip = createGzip();
          fileStream.pipe(gzip).pipe(res);
        } else {
          fileStream.pipe(res);
        }
      }
    } catch (error) {
      throw new HttpException('File not found', HttpStatus.NOT_FOUND);
    }
  }
}
